//
//  NativeCameraController.m
//  Runner
//
//  Created by tock on 2023/9/20.
//
#import <AVFoundation/AVFoundation.h>
#import "NativeCameraController.h"
#import "CameraBottomView.h"
#import "GlobalMacros.h"
#import "EXTScope.h"
#import "UIImage+Extend.h"
@interface NativeCameraController ()<BSVideoBottomViewDelegate,AVCapturePhotoCaptureDelegate,AVCaptureVideoDataOutputSampleBufferDelegate,AVCaptureAudioDataOutputSampleBufferDelegate>
@property(nonatomic,copy) CameraCallback callback;
@property (nonatomic ,strong) CameraBottomView *bottomView;
@property (nonatomic ,strong) UIImageView *photoImageView;
@property(nonatomic) dispatch_queue_t sessionQueue;
@property (nonatomic ,strong) UIButton *ligntBtn;
@property (nonatomic, strong)UIView *navBar;
@property (nonatomic, strong)UIButton*goBack;
@property (nonatomic ,strong) AVCaptureSession *session;
@property (nonatomic ,strong) AVCaptureDevice *device;
@property (nonatomic ,strong) AVCaptureDeviceInput *deviceInput;
@property (nonatomic ,strong) AVCaptureOutput *outPut;
@property (nonatomic ,strong) AVCaptureVideoPreviewLayer *previewLayer;
@property (nonatomic ,strong) AVCaptureConnection *connection;


@end

@implementation NativeCameraController
+(NativeCameraController *) doOpenCameraDetectionWithAction:(CameraCallback)callback{
    NativeCameraController *livenessVc = [[NativeCameraController alloc]init];
    livenessVc.callback = callback;
    return livenessVc;
}

-(CameraBottomView *)bottomView{
    if (!_bottomView) {
        _bottomView = [[CameraBottomView alloc]initWithFrame:CGRectMake(0, SCREEN_HEIGHT-150, SCREEN_WIDTH, 150)];
        _bottomView.delegate = self;
    }
    return _bottomView;
}
-(UIImageView *)photoImageView{
    if (!_photoImageView) {
        _photoImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 64, SCREEN_WIDTH, SCREEN_HEIGHT-150-64)];
        _photoImageView.contentMode = UIViewContentModeScaleAspectFill;
        _photoImageView.layer.masksToBounds = YES;
        _photoImageView.hidden = YES;
    }
    return _photoImageView;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor blackColor];
    
    [self createQueue];
    [self authorization];
    
    
}

-(void)authorization{
    //请求相机权限
    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    
    if (status == AVAuthorizationStatusNotDetermined) {
        
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            
            
            dispatch_async(dispatch_get_main_queue(), ^{
                if (granted) {
                    [self authorization];
                }else{
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"" message:@"相机权限未开启,请前往 手机-设置 开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
                    UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                        
                        [self back];
                    }];
                    
                    [controller addAction:action];
                    [self presentViewController:controller animated:YES completion:nil];
                    return;
                }
            });
        }];
        
    }else if (status == AVAuthorizationStatusDenied) {
        
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"" message:@"相机权限未开启,请前往 手机-设置 开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            
            [self back];
        }];
        
        [controller addAction:action];
        [self presentViewController:controller animated:YES completion:nil];
        
        return;
    }else if (status == AVAuthorizationStatusAuthorized){
        [self configData];
        [self initSubViews];
        
    }
}
-(void)initSubViews{
    [self.view addSubview:self.photoImageView];
    [self.view addSubview:self.bottomView];
    [self.view addSubview:self.navBar];
}

-(UIView*)navBar{
    if (!_navBar) {
        _navBar = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 64)];
        [_navBar addSubview:self.goBack];
        [_navBar addSubview:self.ligntBtn];
    }
    return _navBar;
}
-(UIButton*)goBack{
    if (!_goBack) {
        _goBack = [UIButton buttonWithType:UIButtonTypeCustom];
        _goBack.frame = CGRectMake(15, 15, 100, 60);
        _goBack.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        UIImage *theImage = [[UIImage imageNamed:@"navi_back"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
        _goBack .tintColor = [UIColor whiteColor];
        [_goBack setImage:theImage forState:UIControlStateNormal];
        [_goBack addTarget:self action:@selector(clickedBackBtn:) forControlEvents:UIControlEventTouchUpInside];
        [_navBar addSubview:_goBack];
    }
    return _goBack;
}
-(UIButton *)ligntBtn{
    if (!_ligntBtn) {
        _ligntBtn = [[UIButton alloc]initWithFrame:CGRectMake(SCREEN_WIDTH-45, 15, 35, 35)];
        [_ligntBtn setImage:[UIImage imageNamed:@"photo_camera_light_off"] forState:UIControlStateNormal];
        [_ligntBtn addTarget:self action:@selector(ligntBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _ligntBtn;;
}
-(void)configData{
    
    self.session = [[AVCaptureSession alloc]init];
    if ([self.session canSetSessionPreset:AVCaptureSessionPresetHigh]){
        self.session.sessionPreset = AVCaptureSessionPresetHigh;
    }else if ([self.session canSetSessionPreset:AVCaptureSessionPresetiFrame960x540]) {
        self.session.sessionPreset = AVCaptureSessionPresetiFrame960x540;
    }
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //如果不放在子线程里，跳转到相机的时候，会卡
        [self addPicIO];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
            self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
            self.previewLayer.frame = CGRectMake(0, 64, SCREEN_WIDTH, SCREEN_HEIGHT-150-64);
            [self.view.layer insertSublayer:self.previewLayer atIndex:0];
            [self initializeShapeLayer];
            [self sessionStartRunning];
        });
    });
}
-(void)addPicIO{
    NSError *error = nil;
    self.deviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:&error];
    if (!error) {
        if ([self.session canAddInput:self.deviceInput]) {
            [self.session addInput:self.deviceInput];
        }
        if ([self.session canAddOutput:self.outPut]) {
            [self.session addOutput:self.outPut];
        }
    }
}

- (void)createQueue{
    dispatch_queue_t sessionQueue = dispatch_queue_create("com.session.queue", DISPATCH_QUEUE_SERIAL);
    self.sessionQueue = sessionQueue;
}

-(void)sessionStartRunning{
    
    @weakify(self);
    dispatch_async(self.sessionQueue, ^{
        @strongify(self);
        if (!self.session.running) {
            [self.session startRunning];
        }
    });
}


-(void)sessionStopRunning{
    
    @weakify(self);
    dispatch_async(self.sessionQueue, ^{
        @strongify(self);
        if (self.session.running) {
            [self.session stopRunning];
        }
    });
}

-(void)dealloc{
    if( self.callback){
        self.callback = nil;
    }
    if ([self.device lockForConfiguration:nil]) {
        if ([self.device isTorchModeSupported:AVCaptureTorchModeOff]) {
            self.device.flashMode = AVCaptureFlashModeOff;
            self.device.torchMode = AVCaptureTorchModeOff;
        }
        [self.device unlockForConfiguration];
    }
}

- (void)initializeShapeLayer{
    
    CGFloat  width =   (SCREEN_WIDTH - 100);
    CGFloat  higth =   (SCREEN_HEIGHT - 360);
    //中间空心洞的区域
    CGRect cutRect = CGRectMake((SCREEN_WIDTH - width)/2.0,150.0, width, higth);
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0,64, SCREEN_WIDTH,SCREEN_HEIGHT-150-64)];
    
    // 挖空心洞 显示区域
    UIBezierPath *cutRectPath = [UIBezierPath bezierPathWithRect:cutRect];
    
    //将circlePath添加到path上
    [path appendPath:cutRectPath];
    path.usesEvenOddFillRule = YES;
    
    //显示遮罩层
    CAShapeLayer*fillLayer = [CAShapeLayer layer];
    fillLayer.path = path.CGPath;
    fillLayer.fillRule = kCAFillRuleEvenOdd;
    fillLayer.opacity = 0.6;//透明度
    fillLayer.backgroundColor = [UIColor orangeColor].CGColor;
    [self.view.layer addSublayer:fillLayer];
    
    
    // 边界校准线
    CGFloat lineWidth = 2;
    CGFloat lineLength = 20;
    UIBezierPath *linePath = [UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth,
                                                                         cutRect.origin.y - lineWidth,
                                                                         lineLength,
                                                                         lineWidth)];
    //追加路径
    [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth,
                                                                     cutRect.origin.y - lineWidth,
                                                                     lineWidth,
                                                                     lineLength)]];
    
    [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width - lineLength + lineWidth,
                                                                     cutRect.origin.y - lineWidth,
                                                                     lineLength,
                                                                     lineWidth)]];
    [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width ,
                                                                     cutRect.origin.y - lineWidth,
                                                                     lineWidth,
                                                                     lineLength)]];
    
    [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth,
                                                                     cutRect.origin.y + cutRect.size.height - lineLength + lineWidth,
                                                                     lineWidth,
                                                                     lineLength)]];
    [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth,
                                                                     cutRect.origin.y + cutRect.size.height,
                                                                     lineLength,
                                                                     lineWidth)]];
    
    [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width,
                                                                     cutRect.origin.y + cutRect.size.height - lineLength + lineWidth,
                                                                     lineWidth,
                                                                     lineLength)]];
    [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width - lineLength + lineWidth,
                                                                     cutRect.origin.y + cutRect.size.height,
                                                                     lineLength,
                                                                     lineWidth)]];
    
    CAShapeLayer*pathLayer = [CAShapeLayer layer];
    pathLayer.path = linePath.CGPath;
    pathLayer.fillColor = UIColorFromRGB(UISerScanColor).CGColor;
    [self.view.layer addSublayer:pathLayer];
}

-(void)clickedBackBtn:(UIButton *)sender{
    self.callback(nil);
    [self.navigationController popViewControllerAnimated:YES];
}
//UIImage -> Base64图片
+ (BOOL) imageHasAlpha: (UIImage *) image
{
    CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image.CGImage);
    return (alpha == kCGImageAlphaFirst ||
            alpha == kCGImageAlphaLast ||
            alpha == kCGImageAlphaPremultipliedFirst ||
            alpha == kCGImageAlphaPremultipliedLast);
}

+ (UIImage *)resizeImage:(UIImage*)image{

    
  return image;
}

+ (NSString*) image2DataURL: (UIImage *) image{

    NSString *mimeType  = @"image/png";
    //进行压缩
    double finalSize = 512 * 1024.0;
    NSData*data = UIImageJPEGRepresentation(image, 1.0f);
    CGFloat _quality = finalSize /data.length;
    for (CGFloat quality = _quality; quality >= 0; quality -= 0.05)
    {
        data = UIImageJPEGRepresentation(image,quality);
        if (data.length < finalSize)
            break;
    }
    return [NSString stringWithFormat:@"data:%@;base64,%@", mimeType,
            [data base64EncodedStringWithOptions: 0]];
}

-(void)back{
    UIImage *image = [self getWaterMarkImageWithOriginImage:self.photoImageView.image];
    if(image){
        CGFloat  width =  SCREEN_WIDTH-60;
        CGFloat x =    (SCREEN_WIDTH - width)/2.0+10;
        UIImage*cutImg = [UIImage cutImageBuffer:image cutWithOptions:@{@"x":@(x) ,@"y":@150,@"width":@(SCREEN_WIDTH),@"height":@(SCREEN_HEIGHT) }];
        NSString* base64Img = [self.class image2DataURL:cutImg];
        self.callback(base64Img);
    }else{
        self.callback(nil);
    }

    [self.navigationController popViewControllerAnimated:YES];
}



- (void)BSVideoBottomView:(CameraBottomView *)bottomView didClickFuncBtnWithType:(FUNCTYPE)funcType {
    
    NSLog(@"hahah---%ld",funcType);
    
    switch (funcType) {
        case FUNC_TYPE_BACK:{
        }
            break;
        case FUNC_TYPE_RETRY:{        //重拍
            [self sessionStartRunning];
            self.photoImageView.hidden = YES;

        }
            break;
        case FUNC_TYPE_NEXT:{   //点击下一步
            [self nextStep];
        }
            break;
        case FUNC_TYPE_PIC:{   //拍照
            [self takePicture];
        }
            break;
        case FUNC_TYPE_VIDEO:{//视频录制
            
        }break;
        default:
            break;
    }
}

//拍照
-(void)takePicture{
    

    if (@available(iOS 10.0, *)) {

        AVCapturePhotoOutput *outPut = (AVCapturePhotoOutput *)self.outPut;
        AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettingsWithFormat:@{AVVideoCodecKey:AVVideoCodecTypeJPEG}];
        [outPut capturePhotoWithSettings:settings delegate:self];
   
    }else{
        
        // 兼容iOS 10以下机型，未测试，不清楚可不可以用，没有iOS10以下机器
        self.connection = [self.outPut connectionWithMediaType:AVMediaTypeVideo];
        [self.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];

        AVCaptureStillImageOutput *outPut = (AVCaptureStillImageOutput *)self.outPut;

        [outPut captureStillImageAsynchronouslyFromConnection:self.connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

            [self sessionStopRunning];

    
            NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [UIImage imageWithData:jpegData];
            self.photoImageView.image = image;
            self.photoImageView.hidden = NO;
            self.previewLayer.hidden = YES;
        }];
    }

    if ([self.delegate respondsToSelector:@selector(photoCameraTakeBtnClicked)]) {
        [self.delegate photoCameraTakeBtnClicked];
    }
}


// 下一步
-(void)nextStep{
    [self back];
}
- (void)turnTorchOn:(BOOL)on{
    
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        
        if ([device hasTorch] && [device hasFlash]){
            
            [device lockForConfiguration:nil];
            if (on) {
                [device setTorchMode:AVCaptureTorchModeOn];
                [device setFlashMode:AVCaptureFlashModeOn];
                
            } else {
                [device setTorchMode:AVCaptureTorchModeOff];
                [device setFlashMode:AVCaptureFlashModeOff];
            }
            [device unlockForConfiguration];
        }
    }
}

/// 闪光灯
-(void)ligntBtnClick:(UIButton*)button{
    button.selected = !button.selected;
    if (button.selected) {
        [self.ligntBtn setImage:[UIImage imageNamed:@"photo_camera_light_on"] forState:UIControlStateNormal];
        [self turnTorchOn:YES];
    }
    else{
        [_ligntBtn setImage:[UIImage imageNamed:@"photo_camera_light_off"] forState:UIControlStateNormal];
        [self turnTorchOn:NO];
    }

}
#pragma mark - 图片存储相关
// 不支持图片方向重定位（如果是前置摄像头，没有做成像翻转。iOS11支持，走didFinishProcessingPhoto方法）
-(void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhotoSampleBuffer:(CMSampleBufferRef)photoSampleBuffer previewPhotoSampleBuffer:(CMSampleBufferRef)previewPhotoSampleBuffer resolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings bracketSettings:(AVCaptureBracketedStillImageSettings *)bracketSettings error:(NSError *)error API_AVAILABLE(ios(10.0)){

    if (photoSampleBuffer) {

        [self sessionStopRunning];
        NSData *data = [AVCapturePhotoOutput JPEGPhotoDataRepresentationForJPEGSampleBuffer:photoSampleBuffer previewPhotoSampleBuffer:previewPhotoSampleBuffer];
        UIImage *image = [UIImage imageWithData:data];

        self.photoImageView.image = image;
        self.photoImageView.hidden = NO;
    }
}


///不同于上边的方法，此方法拿到的是CGImageRef ，通过- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation API_AVAILABLE(ios(4.0));方法，重新对图片进行方向调整

-(void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo error:(NSError *)error API_AVAILABLE(ios(11.0)){

    if (photo) {
        [self sessionStopRunning];
        CGImageRef imageRef = [photo CGImageRepresentation];
       
        UIImage * image = nil;
        /// 调整图片方向
        if (self.device.position == AVCaptureDevicePositionFront) {
            image = [[UIImage alloc]initWithCGImage:imageRef scale:[UIScreen mainScreen].scale orientation:UIImageOrientationLeftMirrored];
        }else{
            image = [[UIImage alloc]initWithCGImage:imageRef scale:[UIScreen mainScreen].scale orientation:UIImageOrientationRight];
        }
       
        self.photoImageView.image = image;
        self.photoImageView.hidden = NO;
    }
}



#pragma mark - 图片存储相关
-(UIImage *)getWaterMarkImageWithOriginImage:(UIImage *)originImage{

    UIGraphicsBeginImageContextWithOptions(self.photoImageView.bounds.size, NO, [UIScreen mainScreen].scale);
    [self.photoImageView.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}


-(void)saveWaterMarkImage:(UIImage *)waterMarkImage{

    UIImageWriteToSavedPhotosAlbum(waterMarkImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}



-(void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {

    if(error){
        [self back];
    }else{
        
        if ([self.delegate respondsToSelector:@selector(photoCameraNextBtnClickedWithImage:)]) {

            UIImage *image = [self getWaterMarkImageWithOriginImage:self.photoImageView.image];
            [self.delegate photoCameraNextBtnClickedWithImage:image];
        }

        [self back];
    }
}




#pragma mark - init 属性初始化


-(AVCaptureDevice *)device{
    if (!_device) {
        _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        [_device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus];
    }
    return _device;
}


-(AVCaptureOutput *)outPut{
    
    if (!_outPut) {
        if (@available(iOS 10.0, *)) {
            _outPut = [[AVCapturePhotoOutput alloc]init];
        } else {
            _outPut = [[AVCaptureStillImageOutput alloc]init];
            NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
            [(AVCaptureStillImageOutput *)_outPut setOutputSettings:outputSettings];
        }
    }
    return _outPut;
}


@end
